#pragma once

#include <stdbool.h>
#include <stdint.h>

#include "luster_dynarr.hh"
#include "luster_lexpr.hh"
#include "luster_status.hh"

namespace luster {

#define CTYPE_MAP(_) \
	_(IDK) \
	_(INT) \
	_(UINT) \
	_(ISIZE) \
	_(USIZE) \
	_(BOOL) \
	_(CHAR) \
	_(CONST) \
	_(PTR) \
	_(ARR)

typedef enum ctype_type {
#define _(M_NAME) CTYPE_##M_NAME,
	CTYPE_MAP(_)
#undef _
} ctype_tag_t;

typedef struct ctype ctype_t;

typedef struct ctype_arr {
	ctype_t *element_type;
	uintptr_t len;
} ctype_arr_t;

typedef struct ctype {
	ctype_tag_t tag{ctype_tag_t::CTYPE_BOOL};
	union {
		ctype_t *type;
		ctype_arr_t array;
	} u{.type = nullptr};
} ctype_t;

ctype_t *ctype_init_const(ctype_t *ctype);
ctype_t *ctype_init_ptr(ctype_t *ctype);
bool ctype_eq(ctype_t lhs, ctype_t rhs);
void ctype_deinit(ctype_t *ctype);

#define CITEM_TYPE_MAP(_) \
	/* 字面值 */ \
	_(I32) \
	_(F32) \
	_(BOOL) \
	_(STRING) \
\
	/* 标识符 */ \
	_(VAR) \
\
	/* 四则运算 */ \
	_(ADD) \
	_(SUB) \
	_(MUL) \
	_(DIV) \
\
	/* 逻辑运算 */ \
	_(NOT) \
	_(AND) \
	_(OR) \
\
	/* 变量定义 */ \
	_(LET) \
\
	/* 变量赋值 */ \
	_(SET)

typedef enum citem_type {
#define _(M_NAME) CITEM_##M_NAME,
	CITEM_TYPE_MAP(_)
#undef _
} citem_tag_t;

char const *citem_type_name(citem_tag_t ctype);

typedef struct citem citem_t;

luster_declare_dynarr(clist, citem_t);

static inline bool citem_is_expr(citem_tag_t tp) {
	switch (tp) {
	case CITEM_I32:
	case CITEM_F32:
	case CITEM_BOOL:
	case CITEM_STRING:
	case CITEM_VAR:
	case CITEM_ADD:
	case CITEM_SUB:
	case CITEM_MUL:
	case CITEM_DIV:
	case CITEM_NOT:
	case CITEM_AND:
	case CITEM_OR:
		return true;
	default:
		return false;
	};
}

typedef struct citem {
	citem_tag_t tag{citem_tag_t::CITEM_I32};

	union {
		int32_t i32;
		float f32;
		bool yes;
		luster::Slice string;
		clist_t clist;
	} u{.i32 = 0};

	ctype_t type{};
} citem_t;

typedef struct translator {
	int x;
} translator_t;

Status translate(translator_t *t, Lexpr *s, citem_t *c);

void citem_deinit(citem_t *citem);

typedef struct citem_display_opt {
	bool need_bracket;
} citem_display_opt_t;

Status citem_display_opt(citem_t const *c, FILE *fp, citem_display_opt_t opt);

#define citem_display(M_c, M_fp, ...) \
	luster::citem_display_opt( \
		M_c, M_fp, (luster::citem_display_opt_t){__VA_ARGS__});

} // namespace luster
